package maple.thelittleredbook.user.service;

import lombok.extern.slf4j.Slf4j;
import maple.thelittleredbook.common.service.EmailService;
import maple.thelittleredbook.user.dto.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import maple.thelittleredbook.common.util.JwtTokenUtil;
import maple.thelittleredbook.user.entity.User;
import maple.thelittleredbook.user.entity.UserProfile;
import maple.thelittleredbook.user.mapper.UserMapper;
import maple.thelittleredbook.user.mapper.UserProfileMapper;

import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.LocalDateTime;
import java.util.Base64;

@Slf4j
@Service
public class UserService {

    private final UserMapper userMapper;
    private final UserProfileMapper userProfileMapper;
    private final PasswordEncoder passwordEncoder;
    private final VerificationService verificationService;
    private final JwtTokenUtil jwtTokenUtil;
    private final EmailService emailService;

    @Value("${file.server.url}")
    private String fileServerUrl;

    @Value("${file.server.auth.username}")
    private String fileServerUsername;

    @Value("${file.server.auth.password}")
    private String fileServerPassword;

    @Value("${file.avatar.default-path}")
    private String defaultAvatarPath;

    @Autowired
    public UserService(UserMapper userMapper,
                       UserProfileMapper userProfileMapper,
                       PasswordEncoder passwordEncoder,
                       VerificationService verificationService,
                       JwtTokenUtil jwtTokenUtil, EmailService emailService) {
        this.userMapper = userMapper;
        this.userProfileMapper = userProfileMapper;
        this.passwordEncoder = passwordEncoder;
        this.verificationService = verificationService;
        this.jwtTokenUtil = jwtTokenUtil;
        this.emailService = emailService;
    }

    /**
     * 普通用户注册
     *
     * @param registrationDTO 注册信息
     * @return 注册结果DTO
     */
    @Transactional
    public UserDTO registerUser(UserRegistrationDTO registrationDTO) {
        String username = registrationDTO.getUsername();
        String email = registrationDTO.getEmail();
        String password = registrationDTO.getPassword();
        String verificationCode = registrationDTO.getVerificationCode();
        String bio = registrationDTO.getBio();

        // 1. 验证邮箱和验证码
        if (!verificationService.verifyCode(email, verificationCode, "email_verification")) {
            throw new IllegalArgumentException("验证码无效或已过期");
        }

        // 2. 检查用户名是否已存在
        if (userMapper.selectByUsername(username) != null) {
            throw new IllegalArgumentException("用户名已存在");
        }

        // 3. 检查邮箱是否已注册
        if (userMapper.selectByEmail(email) != null) {
            throw new IllegalArgumentException("邮箱已注册");
        }

        try {
            // 4. 创建并插入用户
            User user = new User();
            user.setUsername(username);
            user.setEmail(email);
            user.setPassword(passwordEncoder.encode(password));
            user.setBio(bio);
            user.setRole("USER");
            user.setIsActive(true);
            user.setCreatedAt(LocalDateTime.now());
            user.setUpdatedAt(LocalDateTime.now());

            userMapper.insert(user);
            Long userId = user.getId();

            // 5. 设置默认头像（失败不影响注册）
            try {
                String avatarUrl = copyDefaultAvatarAndGetUrl(userId);
                if (avatarUrl != null) {
                    user.setAvatar(avatarUrl);
                    userMapper.updateById(user);
                }
            } catch (Exception e) {
                log.error("设置默认头像失败: {}", e.getMessage());
            }

            // 6. 创建用户画像
            UserProfile userProfile = createDefaultUserProfile(userId);
            userProfileMapper.insert(userProfile);

            // 7. 使验证码失效
            verificationService.invalidateAllCodes(email, "email_verification");

            // 8. 构建并返回 DTO
            UserDTO userDTO = convertToDTO(user);
            log.info("用户注册成功: userId={}, username={}, email={}", userId, username, email);

            return userDTO;
        } catch (Exception e) {
            if (!(e instanceof IllegalArgumentException)) {
                log.error("用户注册失败: {}", e.getMessage());
                throw new RuntimeException("用户注册失败", e);
            }
            throw e;
        }
    }


    /**
     * 管理员注册（需要超级管理员审核）
     *
     * @param registrationDTO 注册信息
     * @return 注册结果DTO
     */
    @Transactional
    public UserDTO registerAdmin(UserRegistrationDTO registrationDTO) {
        String username = registrationDTO.getUsername();
        String email = registrationDTO.getEmail();
        String password = registrationDTO.getPassword();
        String verificationCode = registrationDTO.getVerificationCode();
        String bio = registrationDTO.getBio();

        // 1. 验证邮箱和验证码
        if (!verificationService.verifyCode(email, verificationCode, "email_verification")) {
            throw new IllegalArgumentException("验证码无效或已过期");
        }

        // 2. 检查用户名是否已存在
        if (userMapper.selectByUsername(username) != null) {
            throw new IllegalArgumentException("用户名已存在");
        }

        // 3. 检查邮箱是否已注册
        if (userMapper.selectByEmail(email) != null) {
            throw new IllegalArgumentException("邮箱已注册");
        }

        try {
            // 4. 创建并插入管理员用户（未激活状态）
            User user = new User();
            user.setUsername(username);
            user.setEmail(email);
            user.setPassword(passwordEncoder.encode(password));
            user.setBio(bio);
            user.setRole("ADMIN");
            user.setIsActive(false);  // 管理员注册时未激活，需要审核
            user.setCreatedAt(LocalDateTime.now());
            user.setUpdatedAt(LocalDateTime.now());

            userMapper.insert(user);
            Long userId = user.getId();

            // 5. 创建用户画像
            UserProfile userProfile = createDefaultUserProfile(userId);
            userProfileMapper.insert(userProfile);

            // 6. 使验证码失效
            verificationService.invalidateAllCodes(email, "email_verification");

            // 7. 发送管理员申请邮件给超级管理员（事务内，失败则回退）
            boolean emailSent = emailService.sendAdminApplicationEmail(email, username, userId, bio);
            if (!emailSent) {
                throw new RuntimeException("发送管理员申请邮件失败，注册已取消");
            }
            log.info("管理员申请邮件已发送至超级管理员");

            // 8. 设置默认头像（在事务外操作，失败不影响注册）
            try {
                String avatarUrl = copyDefaultAvatarAndGetUrl(userId);
                if (avatarUrl != null) {
                    user.setAvatar(avatarUrl);
                    userMapper.updateById(user);
                }
            } catch (Exception e) {
                log.error("设置默认头像失败: {}", e.getMessage());
                // 头像设置失败不影响注册，因为邮件已发送成功
            }

            // 9. 构建并返回 DTO
            UserDTO userDTO = convertToDTO(user);
            log.info("管理员注册成功，等待审核: userId={}, username={}, email={}", userId, username, email);

            return userDTO;
        } catch (Exception e) {
            if (!(e instanceof IllegalArgumentException)) {
                log.error("管理员注册失败: {}", e.getMessage());
                throw new RuntimeException("管理员注册失败", e);
            }
            throw e;
        }
    }


    /**
     * 审核管理员申请（统一入口）
     *
     * @param userId 申请人用户ID
     * @param approved 是否通过
     * @param reviewerUserId 审核人用户ID
     * @param rejectReason 拒绝原因（仅拒绝时需要）
     * @return 是否成功
     */
    @Transactional
    public boolean reviewAdminApplication(Long userId, Boolean approved, Long reviewerUserId, String rejectReason) {
        // 获取审核人信息
        User reviewer = userMapper.selectById(reviewerUserId);
        if (reviewer == null) {
            throw new IllegalArgumentException("审核人不存在");
        }

        if (approved) {
            return approveAdminApplication(userId, reviewer.getUsername());
        } else {
            // 拒绝时，检查拒绝原因
            if (rejectReason == null || rejectReason.trim().isEmpty()) {
                throw new IllegalArgumentException("拒绝申请时必须提供拒绝原因");
            }
            return rejectAdminApplication(userId, reviewer.getUsername(), rejectReason);
        }
    }


    /**
     * 审核通过管理员申请
     *
     * @param userId 申请人用户ID
     * @param reviewerUsername 审核人用户名
     * @return 是否成功
     */
    @Transactional
    public boolean approveAdminApplication(Long userId, String reviewerUsername) {
        // 1. 查找申请人
        User applicant = userMapper.selectById(userId);
        if (applicant == null) {
            throw new IllegalArgumentException("申请人不存在");
        }

        // 2. 检查申请人状态
        if (!"ADMIN".equals(applicant.getRole())) {
            throw new IllegalArgumentException("该用户不是管理员申请");
        }

        if (Boolean.TRUE.equals(applicant.getIsActive())) {
            throw new IllegalArgumentException("该管理员已激活，无需重复审核");
        }

        // 3. 激活管理员账户
        applicant.setIsActive(true);
        applicant.setUpdatedAt(LocalDateTime.now());
        userMapper.updateById(applicant);

        // 4. 发送审核通过邮件给申请人
        boolean emailSent = emailService.sendAdminReviewResultEmail(
                applicant.getEmail(),
                applicant.getUsername(),
                true,
                reviewerUsername,
                null
        );

        if (!emailSent) {
            throw new RuntimeException("发送审核结果邮件失败");
        }

        log.info("管理员申请审核通过: userId={}, username={}, reviewer={}",
                userId, applicant.getUsername(), reviewerUsername);
        return true;
    }

    /**
     * 拒绝管理员申请
     *
     * @param userId 申请人用户ID
     * @param reviewerUsername 审核人用户名
     * @param rejectReason 拒绝原因
     * @return 是否成功
     */
    @Transactional
    public boolean rejectAdminApplication(Long userId, String reviewerUsername, String rejectReason) {
        // 1. 查找申请人
        User applicant = userMapper.selectById(userId);
        if (applicant == null) {
            throw new IllegalArgumentException("申请人不存在");
        }

        // 2. 检查申请人状态
        if (!"ADMIN".equals(applicant.getRole())) {
            throw new IllegalArgumentException("该用户不是管理员申请");
        }

        if (Boolean.TRUE.equals(applicant.getIsActive())) {
            throw new IllegalArgumentException("该管理员已激活，无法拒绝");
        }

        // 3. 删除申请人记录（或者可以标记为拒绝状态）
        userMapper.deleteById(userId);

        // 同时删除相关的用户画像
        UserProfile profile = userProfileMapper.selectByUserId(userId);
        if (profile != null) {
            userProfileMapper.deleteById(profile.getId());
        }

        // 4. 发送审核拒绝邮件给申请人（失败则抛出异常）
        boolean emailSent = emailService.sendAdminReviewResultEmail(
                applicant.getEmail(),
                applicant.getUsername(),
                false,
                reviewerUsername,
                rejectReason
        );

        if (!emailSent) {
            throw new RuntimeException("发送拒绝通知邮件失败");
        }

        log.info("管理员申请被拒绝: userId={}, username={}, reviewer={}, reason={}",
                userId, applicant.getUsername(), reviewerUsername, rejectReason);
        return true;
    }


    /**
     * 用户登录
     *
     * @param loginRequestDTO 登录请求
     * @return 登录响应DTO
     */
    public LoginResponseDTO login(LoginRequestDTO loginRequestDTO) {
        String account = loginRequestDTO.getAccount();
        String password = loginRequestDTO.getPassword();

        // 查找用户（支持用户名或邮箱登录）
        User user = userMapper.selectByUsernameOrEmail(account);

        if (user == null) {
            throw new IllegalArgumentException("用户不存在或密码错误");
        }

        // 验证密码
        if (!passwordEncoder.matches(password, user.getPassword())) {
            throw new IllegalArgumentException("用户不存在或密码错误");
        }

        // 检查用户状态
        if (!Boolean.TRUE.equals(user.getIsActive())) {
            throw new IllegalArgumentException("账户已被禁用或未激活");
        }


        // 生成JWT令牌
        String token = jwtTokenUtil.generateToken(user.getId(), user.getRole(), user.getIsActive());

        // 创建登录响应
        LoginResponseDTO responseDTO = new LoginResponseDTO();
        responseDTO.setToken(token);
        responseDTO.setUser(convertToDTO(user));

        log.info("用户登录成功: userId={}, username={}", user.getId(), user.getUsername());
        return responseDTO;
    }

    /**
     * 通过验证码重置密码
     *
     * @param email 邮箱
     * @param verificationCode 验证码
     * @param newPassword 新密码
     * @return 是否成功
     */
    @Transactional
    public boolean resetPasswordByCode(String email, String verificationCode, String newPassword) {
        // 验证邮箱和验证码
        if (!verificationService.verifyCode(email, verificationCode, "password_reset")) {
            throw new IllegalArgumentException("验证码无效或已过期");
        }

        // 查找用户
        User user = userMapper.selectByEmail(email);
        if (user == null) {
            throw new IllegalArgumentException("用户不存在");
        }

        // 更新密码
        user.setPassword(passwordEncoder.encode(newPassword));
        user.setUpdatedAt(LocalDateTime.now());
        userMapper.updateById(user);

        // 使所有验证码失效
        verificationService.invalidateAllCodes(email, "password_reset");

        log.info("用户密码重置成功: userId={}, email={}", user.getId(), email);
        return true;
    }

    /**
     * 使用旧密码修改密码
     *
     * @param userId 用户ID
     * @param oldPassword 旧密码
     * @param newPassword 新密码
     * @return 是否成功
     */
    @Transactional
    public boolean changePassword(Long userId, String oldPassword, String newPassword) {
        // 查找用户
        User user = userMapper.selectById(userId);
        if (user == null) {
            throw new IllegalArgumentException("用户不存在");
        }

        // 验证旧密码
        if (!passwordEncoder.matches(oldPassword, user.getPassword())) {
            throw new IllegalArgumentException("旧密码不正确");
        }

        // 更新密码
        user.setPassword(passwordEncoder.encode(newPassword));
        user.setUpdatedAt(LocalDateTime.now());
        userMapper.updateById(user);

        log.info("用户修改密码成功: userId={}", userId);
        return true;
    }

    /**
     * 更新用户个人信息
     *
     * @param userId 用户ID
     * @param username 用户名
     * @param bio 个人简介
     * @param avatarFile 头像文件
     * @return 更新后的用户信息
     */
    @Transactional
    public UserDTO updateUserProfile(Long userId, String username, String bio, MultipartFile avatarFile) {
        // 获取当前用户信息
        User user = userMapper.selectById(userId);
        if (user == null) {
            throw new IllegalArgumentException("用户不存在");
        }

        boolean needUpdate = false;

        // 更新用户名（如果提供了新的用户名）
        if (username != null && !username.equals(user.getUsername())) {
            // 检查用户名是否已被使用
            User existingUser = userMapper.selectByUsername(username);
            if (existingUser != null && !existingUser.getId().equals(userId)) {
                throw new IllegalArgumentException("用户名已被使用");
            }

            user.setUsername(username);
            needUpdate = true;
        }

        // 更新个人简介
        if (bio != null && !bio.equals(user.getBio())) {
            user.setBio(bio);
            needUpdate = true;
        }

        // 更新头像（如果提供了新的头像文件）
        if (avatarFile != null && !avatarFile.isEmpty()) {
            try {
                String avatarUrl = updateUserAvatar(userId, avatarFile);
                user.setAvatar(avatarUrl);
                needUpdate = true;
            } catch (IOException e) {
                log.error("更新头像失败: {}", e.getMessage());
                throw new RuntimeException("头像上传失败");
            }
        }

        // 如果有更新，则更新数据库
        if (needUpdate) {
            user.setUpdatedAt(LocalDateTime.now());
            userMapper.updateById(user);
            log.info("用户信息更新成功: userId={}", userId);
        }

        // 返回更新后的用户信息
        return convertToDTO(user);
    }

    /**
     * 根据用户ID获取用户信息（查看自己的完整信息）
     */
    public UserDTO getMyProfile(Long userId) {
        User user = userMapper.selectById(userId);
        if (user == null) {
            throw new IllegalArgumentException("用户不存在");
        }
        return convertToDTO(user);
    }

    /**
     * 根据用户ID获取用户信息（查看他人信息，权限控制）
     * @param targetUserId 目标用户ID
     * @param currentUserId 当前用户ID
     * @param currentUserRole 当前用户角色
     * @return 用户信息（根据权限返回不同的DTO）
     */
    public Object getUserProfile(Long targetUserId, Long currentUserId, String currentUserRole) {
        User targetUser = userMapper.selectById(targetUserId);
        if (targetUser == null) {
            throw new IllegalArgumentException("用户不存在");
        }

        // 如果是查看自己的信息，返回完整信息
        if (targetUserId.equals(currentUserId)) {
            return convertToDTO(targetUser);
        }

        // 如果是管理员或超级管理员，返回完整信息
        if ("ADMIN".equals(currentUserRole) || "SUPERADMIN".equals(currentUserRole)) {
            return convertToDTO(targetUser);
        }

        // 普通用户查看他人，只返回公开信息
        return convertToPublicDTO(targetUser);
    }


    /**
     * 通过用户ID刷新JWT Token（优化版本）
     * 避免重复解析JWT，直接使用已知的用户ID
     *
     * @param userId 用户ID
     * @return 新的登录响应DTO
     */
    public LoginResponseDTO refreshTokenByUserId(Long userId) {
        try {
            // 从数据库获取最新的用户信息
            User user = userMapper.selectById(userId);
            if (user == null) {
                throw new IllegalArgumentException("用户不存在");
            }

            // 检查用户状态
            if (!Boolean.TRUE.equals(user.getIsActive())) {
                throw new IllegalArgumentException("账户已被禁用");
            }

            // 生成新的JWT令牌
            String newToken = jwtTokenUtil.generateToken(user.getId(), user.getRole(), user.getIsActive());

            // 创建登录响应
            LoginResponseDTO responseDTO = new LoginResponseDTO();
            responseDTO.setToken(newToken);
            responseDTO.setUser(convertToDTO(user));

            log.info("Token刷新成功(通过userId): userId={}, username={}", user.getId(), user.getUsername());
            return responseDTO;

        } catch (Exception e) {
            if (!(e instanceof IllegalArgumentException)) {
                log.error("Token刷新失败(通过userId): userId={}, error={}", userId, e.getMessage());
                throw new RuntimeException("Token刷新失败", e);
            }
            throw e;
        }
    }

    /**
     * 复制默认头像到用户目录并返回URL
     *
     * @param userId 用户ID
     * @return 头像URL
     * @throws IOException 如果复制失败
     */
    private String copyDefaultAvatarAndGetUrl(Long userId) throws IOException {
        // 读取默认头像
        try (InputStream in = getClass().getResourceAsStream(defaultAvatarPath)) {
            if (in == null) {
                throw new IOException("默认头像文件不存在: " + defaultAvatarPath);
            }

            // 构建目标路径（不需要创建文件夹，直接上传）
            String fileName = "avatar.jpg"; // 固定的文件名
            String filePath = "springboot/littleRedBook/user/" + userId + "/" + fileName;

            // 上传到文件服务器
            HttpClient client = HttpClient.newBuilder()
                    .version(HttpClient.Version.HTTP_1_1)
                    .build();

            String auth = Base64.getEncoder().encodeToString((fileServerUsername + ":" + fileServerPassword).getBytes());

            // 直接上传文件，不需要先创建目录
            HttpRequest request = HttpRequest.newBuilder()
                    .uri(URI.create(fileServerUrl + "/files/" + filePath))
                    .header("Authorization", "Basic " + auth)
                    .header("Content-Type", "image/jpeg")
                    .PUT(HttpRequest.BodyPublishers.ofInputStream(() -> {
                        try {
                            return getClass().getResourceAsStream(defaultAvatarPath);
                        } catch (Exception e) {
                            throw new UncheckedIOException(new IOException("读取默认头像失败", e));
                        }
                    }))
                    .build();

            HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());

            if (response.statusCode() >= 200 && response.statusCode() < 300) {
                return fileServerUrl + "/files-get/" + filePath;
            } else {
                throw new IOException("上传头像失败，状态码: " + response.statusCode());
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new IOException("上传头像被中断", e);
        }
    }

    /**
     * 从文件服务器删除文件
     * @param userId 用户ID
     * @param fileName 文件名
     * @throws IOException 如果删除失败
     */
    private void deleteFileFromServer(Long userId, String fileName) throws IOException {
        HttpClient client = HttpClient.newBuilder()
                .version(HttpClient.Version.HTTP_1_1)
                .build();

        String auth = Base64.getEncoder().encodeToString((fileServerUsername + ":" + fileServerPassword).getBytes());
        String filePath = "springboot/littleRedBook/user/" + userId + "/" + fileName;
        String fileUrl = fileServerUrl + "/files/" + filePath;

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(fileUrl))
                .header("Authorization", "Basic " + auth)
                .method("DELETE", HttpRequest.BodyPublishers.noBody())
                .build();

        try {
            HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());

            if (response.statusCode() != 204 && response.statusCode() != 404) {
                // 404是可接受的，意味着文件不存在
                log.warn("删除文件返回状态码: {}, 文件: {}", response.statusCode(), filePath);
            } else {
                log.info("成功删除文件: {}", filePath);
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new IOException("删除文件被中断", e);
        }
    }

    /**
     * 上传文件到服务器
     * @param file 文件
     * @param userId 用户ID
     * @param fileName 文件名
     * @return 文件URL
     * @throws IOException 如果上传失败
     */
    private String uploadFileToServer(MultipartFile file, Long userId, String fileName) throws IOException {
        HttpClient client = HttpClient.newBuilder()
                .version(HttpClient.Version.HTTP_1_1)
                .build();

        String auth = Base64.getEncoder().encodeToString((fileServerUsername + ":" + fileServerPassword).getBytes());
        String filePath = "springboot/littleRedBook/user/" + userId + "/" + fileName;
        String fileUrl = fileServerUrl + "/files/" + filePath;

        // 直接上传文件，不需要先创建目录
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(fileUrl))
                .header("Authorization", "Basic " + auth)
                .header("Content-Type", getContentType(file.getOriginalFilename()))
                .PUT(HttpRequest.BodyPublishers.ofInputStream(() -> {
                    try {
                        return file.getInputStream();
                    } catch (IOException e) {
                        throw new UncheckedIOException(e);
                    }
                }))
                .build();

        try {
            HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());

            if (response.statusCode() >= 200 && response.statusCode() < 300) {
                // 返回公开访问URL
                return fileServerUrl + "/files-get/" + filePath;
            } else {
                throw new IOException("文件上传失败，状态码: " + response.statusCode() + ", 响应: " + response.body());
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new IOException("文件上传被中断", e);
        }
    }

    /**
     * 获取文件的Content-Type
     */
    private String getContentType(String fileName) {
        if (fileName == null) return "application/octet-stream";

        String lowerFileName = fileName.toLowerCase();
        if (lowerFileName.endsWith(".jpg") || lowerFileName.endsWith(".jpeg")) {
            return "image/jpeg";
        } else if (lowerFileName.endsWith(".png")) {
            return "image/png";
        } else if (lowerFileName.endsWith(".gif")) {
            return "image/gif";
        } else if (lowerFileName.endsWith(".webp")) {
            return "image/webp";
        } else {
            return "application/octet-stream";
        }
    }

    /**
     * 验证上传的文件是否为有效的图片格式
     */
    private void validateImageFile(MultipartFile file) {
        if (file == null || file.isEmpty()) {
            throw new IllegalArgumentException("请选择要上传的文件");
        }

        String contentType = file.getContentType();
        if (contentType == null || !contentType.startsWith("image/")) {
            throw new IllegalArgumentException("请上传图片格式的文件");
        }

        // 检查文件大小（限制为5MB）
        long maxSize = 5 * 1024 * 1024; // 5MB
        if (file.getSize() > maxSize) {
            throw new IllegalArgumentException("图片文件大小不能超过5MB");
        }

        // 检查文件扩展名
        String originalFilename = file.getOriginalFilename();
        if (originalFilename != null) {
            String lowerFileName = originalFilename.toLowerCase();
            if (!lowerFileName.endsWith(".jpg") &&
                    !lowerFileName.endsWith(".jpeg") &&
                    !lowerFileName.endsWith(".png") &&
                    !lowerFileName.endsWith(".gif") &&
                    !lowerFileName.endsWith(".webp")) {
                throw new IllegalArgumentException("只支持 JPG、PNG、GIF、WebP 格式的图片");
            }
        }
    }

    /**
     * 更新用户头像
     * @param userId 用户ID
     * @param avatarFile 新头像文件
     * @return 新头像URL
     * @throws IOException 如果上传失败
     */
    private String updateUserAvatar(Long userId, MultipartFile avatarFile) throws IOException {
        // 验证文件
        validateImageFile(avatarFile);

        // 删除旧头像（如果存在）
        try {
            deleteFileFromServer(userId, "avatar.jpg");
        } catch (IOException e) {
            // 删除失败不影响新头像上传，只记录日志
            log.warn("删除旧头像失败: {}", e.getMessage());
        }

        // 上传新头像
        return uploadFileToServer(avatarFile, userId, "avatar.jpg");
    }

    // ===== 私有辅助方法 =====

    /**
     * 创建默认用户画像
     */
    private UserProfile createDefaultUserProfile(Long userId) {
        UserProfile profile = new UserProfile();
        profile.setUserId(userId);
        profile.setDim1(java.math.BigDecimal.valueOf(0.00));
        profile.setDim2(java.math.BigDecimal.valueOf(0.00));
        profile.setDim3(java.math.BigDecimal.valueOf(0.00));
        profile.setDim4(java.math.BigDecimal.valueOf(0.00));
        profile.setDim5(java.math.BigDecimal.valueOf(0.00));
        profile.setDim6(java.math.BigDecimal.valueOf(0.00));
        profile.setDim7(java.math.BigDecimal.valueOf(0.00));
        profile.setDim8(java.math.BigDecimal.valueOf(0.00));
        profile.setLastUpdateTime(LocalDateTime.now());
        profile.setCreatedAt(LocalDateTime.now());
        return profile;
    }

    /**
     * 将User实体转换为DTO
     */
    private UserDTO convertToDTO(User user) {
        UserDTO userDTO = new UserDTO();
        userDTO.setId(user.getId());
        userDTO.setUsername(user.getUsername());
        userDTO.setEmail(user.getEmail());
        userDTO.setAvatar(user.getAvatar());
        userDTO.setBio(user.getBio());
        userDTO.setRole(user.getRole());
        userDTO.setIsActive(user.getIsActive());
        userDTO.setCreatedAt(user.getCreatedAt());
        userDTO.setUpdatedAt(user.getUpdatedAt());
        return userDTO;
    }

    /**
     * 将User实体转换为公开信息DTO
     */
    private UserPublicDTO convertToPublicDTO(User user) {
        UserPublicDTO userPublicDTO = new UserPublicDTO();
        userPublicDTO.setId(user.getId());
        userPublicDTO.setUsername(user.getUsername());
        userPublicDTO.setAvatar(user.getAvatar());
        userPublicDTO.setBio(user.getBio());
        userPublicDTO.setRole(user.getRole());
        return userPublicDTO;
    }
}